package com.tanqing.ddd.domain.aggregate;


import com.tanqing.ddd.domain.aggregate.dto.ParktingParamsDto;
import com.tanqing.ddd.domain.command.CheckOutCommand;
import com.tanqing.ddd.domain.command.CheckinCommand;
import com.tanqing.ddd.domain.command.NotifyPayCommand;
import com.tanqing.ddd.domain.domain.DomainException;
import com.tanqing.ddd.domain.domain.NotRollbackException;
import com.tanqing.ddd.domain.entity.Plate;
import com.tanqing.ddd.domain.event.*;
import com.tanqing.ddd.domain.utils.DateUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Date;

public class ParktingImpl implements Parkting {
    /**
     * 车牌信息
     */
    private Plate plate;

    /**
     * 入场时间
     */
    private Date checkInTime;

    /**
     * 出场书剑
     */
    private Date checkOutTime;

    /**
     * 最后支付时间
     */
    private Date lastPayTime;
    /**
     * 总支付金额
     */
    private BigDecimal totalPayAmount = BigDecimal.ZERO;



    private ParktingParamsDto parktingParamsDto;

    public Plate getPlate() {
        return plate;
    }

    public void setPlate(Plate plate) {
        this.plate = plate;
        this.parktingParamsDto.setPlate(plate);
    }

    public Date getCheckInTime() {
        return checkInTime;
    }

    public void setCheckInTime(Date checkInTime) {

        this.checkInTime = checkInTime;
        this.parktingParamsDto.setCheckInTime(checkInTime);
    }

    public Date getCheckOutTime() {
        return checkOutTime;
    }

    public void setCheckOutTime(Date checkOutTime) {

        this.checkOutTime = checkOutTime;
        this.parktingParamsDto.setCheckOutTime(checkOutTime);
    }

    public Date getLastPayTime() {
        return lastPayTime;
    }

    public void setLastPayTime(Date lastPayTime) {

        this.lastPayTime = lastPayTime;

        this.parktingParamsDto.setLastPayTime(lastPayTime);
    }

    public BigDecimal getTotalPayAmount() {
        return totalPayAmount;
    }

    public void setTotalPayAmount(BigDecimal totalPayAmount) {
        this.totalPayAmount = totalPayAmount;
        this.parktingParamsDto.setTotalPayAmount(totalPayAmount);
    }


    public ParktingImpl() {
        if (parktingParamsDto == null){
            parktingParamsDto = new ParktingParamsDto();
        }
    }

    @Override
    public ParktingParamsDto getParams() {

        ParktingParamsDto parktingParamsDto1 = new ParktingParamsDto();
        parktingParamsDto1.setTotalPayAmount(this.totalPayAmount);
        parktingParamsDto1.setLastPayTime(this.lastPayTime);
        parktingParamsDto1.setPlate(this.plate);
        parktingParamsDto1.setCheckOutTime(this.checkOutTime);
        parktingParamsDto1.setCheckInTime(this.checkInTime);

        return parktingParamsDto1;
    }

    @Override
    public boolean handle(EventQueue eventQueue, CheckinCommand command) {

        //判断是否已经入场了

        if (checkInPark()) {
            eventQueue.enqueue(new CheckInFailEvent(plate, command.getDate(),"该车辆已在场,请勿重复进场"));
            throw  new NotRollbackException("该车辆已在场,请勿重复进场");
//            return false;
        }

        eventQueue.enqueue(new CheckInEvent(plate, command.getDate()));
        this.checkInTime = command.getDate();
        return true;
    }

    public boolean checkInPark() {
        return checkInTime != null;
    }


    /**
     * 计算费用
     *
     * @return
     */
    @Override
    public BigDecimal calculateFeeNow(Date now) {
        Integer hour = 0;
        BigDecimal price = BigDecimal.ONE;
        if (checkInTime == null) {
            new DomainException("车辆尚未入场，不能结算费用");
        }
        if (lastPayTime == null) {
            //未支付 需要支付
            hour = gethour(checkInTime, now);
            return price.multiply(new BigDecimal(hour));
        } else {
            if (DateUtils.addSecond(lastPayTime, 15 * 60).isAfter(LocalDateTime.now())) {
                //已支付 未超过15分钟
                //不需要付钱
                return BigDecimal.ZERO;
//                return totalPayAmount;
            } else {
                //已支付 但是超过了15分钟  补差价
                hour = gethour(checkInTime, now);

                BigDecimal total = price.multiply(new BigDecimal(hour));

                return total.subtract(totalPayAmount);
            }
        }

    }

    @Override
    public boolean handle(EventQueue eventQueue, NotifyPayCommand command) throws DomainException {

        if (!checkInPark()) {
            throw new DomainException("车辆未入场");
        }

        lastPayTime = command.getPayTime();
        totalPayAmount = totalPayAmount.add(command.getAmount());

        eventQueue.enqueue(new PayedEvent(command.getPlate(), lastPayTime, totalPayAmount));
        return true;
    }

    public Integer gethour(Date start, Date end) {
        Integer hour = 0;
        long differenceInMillis = Math.abs(end.getTime() - start.getTime()); // 获取两个日期相差的毫秒数
        int seconds = (int) (differenceInMillis / 1000); // 将毫秒转换成秒

        int i = seconds / 3600;
        if (i * 3600 == seconds) {
            hour = i;
        } else {
            hour = i + 1;
        }
        return hour;
    }


    @Override
    public boolean handle(EventQueue eventQueue, CheckOutCommand command) {

        if (!checkInPark()) {
            eventQueue.enqueue(new CheckoutFailEvent(plate, command.getDate(), "没有在场"));
            return false;
        }

        if (calculateFeeNow(command.getDate()).compareTo(BigDecimal.ZERO) != 0) {
//            eventQueue.enqueue(new CheckoutFailEvent(plate,new Date(), "您还有未支付的费用，请先结清"));
            return false;
        }

        this.checkInTime = null;
        this.lastPayTime = null;
        this.totalPayAmount = BigDecimal.ZERO;
        eventQueue.enqueue(new CheckOutSuccessEvent(plate, command.getDate()));
        return true;
    }
}
